/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package jmodcog2.filter;

/**
 *
 * @author Mitch
 */
public class GaussianBlurFilter extends Filter2D {
    static final int MODE_X_BLUR = 0;
    static final float TWOPI = 2f * (float) Math.PI;
    static final float E = (float) Math.E;
    float sd0;

    public GaussianBlurFilter(GaussianConfig config) {
        super(config);
        this.sd0 = config.getSd0();
    }

    
    

    float gauss_d(float sdSq, float dSq) {
        if (dSq == 0) {
            return gauss_d0(sdSq);
        }
        return (1 / (TWOPI * sdSq)) * exp(-(dSq) / (2 * sdSq));
    }

    float gauss_d0(float sdSq) {
        return 1 / (TWOPI * sdSq);
    }

    int _input_index(int x, int y) {
        return y * input_len_y + x;
    }
//
//    @Override
//    public void run() {
//        int id = getGlobalId();
//        output[id] = blur(id, sd0);
//    }

    float blur(int id, float sd) {
        int x = 0;
        int y = 0;
        x = (id % output_len_y) + (input_len_x - output_len_x)/2;
        y = (id / output_len_y) + (input_len_y - output_len_y)/2;
        float sum_g = 0;
        float sum_v = 0;
        //
        int dx = 0;
        int dy = 0;
        for (dx = (int) floor(-sd * 3); dx <= ceil(sd * 3); dx++) {
            for (dy = (int) floor(-sd * 3); dy <= ceil(sd * 3); dy++) {
                int _x = 0;
                int _y = 0;
                _x = x + dx;
                _y = y + dy;
                if (_x >= 0 && _x < input_len_y && _y >= 0 && _y < input_len_x) {
                    //
                    float g = 0;
                    g = gauss_d(sd * sd, dx * dx + dy * dy);
                    sum_g += g;
                    sum_v += g * input[_input_index(dx + x, dy + y)];
                }
            }
        }
        sum_v *= 1f / sum_g;
        return sum_v;
    }

    @Override
    public float[] getOutput() {
        get(output);
        return output;
    }

    @Override
    public boolean process(float[] input) {
        if(input.length == this.input.length) {
            
            System.arraycopy(input, 0, this.input, 0, input.length);
            put(this.input);
            execute(output_size);
            return true;
        }
        return false;
    }

    @Override
    protected void _run(int mode) {
        throw new UnsupportedOperationException("Not supported yet.");
    }



    protected static class GaussianConfig implements Filter2DConfig {

        public GaussianConfig() {
        }

        @Override
        public int getInputLenX() {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public int getInputLenY() {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public int getOutputLenX() {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public int getOutputLenY() {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public int getInputSize() {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public int getOutputSize() {
            throw new UnsupportedOperationException("Not supported yet.");
        }

        private float getSd0() {
            throw new UnsupportedOperationException("Not yet implemented");
        }
    }
    
}
